﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MBWebService.Server.Proxy;
using MBWebService.Core.Classes;
using System.ServiceModel;
using MBWebService.Core.Logging;
using System.Threading;
using MBWebService.Core.Enums;

namespace MBWebService.Core.Client
{
    public abstract class ClientBase
    {
        private bool isFirstConnectAttempt = true;
        protected MediaBrowserServerClient client;

        public MBWebService.Core.Classes.RemoteDevice Service { get; private set; }
        public MBWebService.Server.Proxy.PlaybackDevice Device { get; private set; }

        public ClientBase(MBWebService.Core.Classes.RemoteDevice serviceName, MBWebService.Server.Proxy.PlaybackDevice device)
        {
            this.Service = serviceName;
            this.Device = device;
        }

        public void ConnectToService()
        {
            PoolForConnection(Service, Device);
        }

        public event EventHandler ServiceStarted;

        public event EventHandler ServiceClosed;

        public ClientConnectionStatus Status { get; private set; } 

        protected abstract IMediaBrowserServerCallback CallbackInstance { get; }

        protected bool TryConnectToService(RemoteDevice server, MBWebService.Server.Proxy.PlaybackDevice device, out MediaBrowserServerClient client)
        {
            client = null;
            bool retVal = false;
            try
            {
                EndpointAddress address = new EndpointAddress(AppSettings.PublisherUri(server));
                InstanceContext context = new InstanceContext(CallbackInstance);
                WSDualHttpBinding binding = new WSDualHttpBinding(WSDualHttpSecurityMode.None);
                binding.ClientBaseAddress = new Uri(string.Format(@"http://{0}:{1}/MbClient", server.DnsName, server.BasePort - 3));
                binding.SendTimeout = TimeSpan.FromSeconds(5);

                client = new MBWebService.Server.Proxy.MediaBrowserServerClient(context, binding, address);
                client.Subscribe(device);
                retVal = true;
            }
            catch (TimeoutException) 
            {
                if (isFirstConnectAttempt)
                    Logger.Instance.LogMessage("Timed out trying to connect to service..");
            }
            catch (Exception ex)
            {
                Logger.Instance.LogMessage("Error connecting to service: {0}", ex.Message);
            }

            isFirstConnectAttempt = false;
            return retVal;
        }

        protected void PoolForConnection(RemoteDevice server, MBWebService.Server.Proxy.PlaybackDevice device)
        {
            ThreadPool.QueueUserWorkItem(o =>
                    {
                        while (true)
                        {
                            if (this.Status != ClientConnectionStatus.Connected)
                            {
                                MediaBrowserServerClient potentialClient = null;
                                if (TryConnectToService(server, device, out potentialClient))
                                {
                                    this.Status = ClientConnectionStatus.Connected;
                                    this.client = potentialClient;
                                    if (this.ServiceStarted != null)
                                    {
                                        ServiceStarted(this, new EventArgs());
                                    }
                                }
                            }
                            else
                            {
                                // test that connection is still active...
                                bool isServiceAlive = false;
                                if (client != null)
                                {
                                    try
                                    {
                                        client.Test();
                                        isServiceAlive = true;
                                    }
                                    catch { }
                                }

                                if (!isServiceAlive)
                                {
                                    this.Status = ClientConnectionStatus.NotConnected;
                                    try
                                    {
                                        this.client.Close();
                                    }
                                    catch { }

                                    this.client = null;

                                    if (ServiceClosed != null)
                                    {
                                        ServiceClosed(this, new EventArgs());
                                    }
                                }
                            }
                            Thread.Sleep(TimeSpan.FromMinutes(1));
                        }
                    });
        }

        public void Unsubscribe()
        {
            try
            {
                if (client != null)
                {
                    client.Unsubscribe(AppSettings.SessionName);
                }
            }
            catch (Exception ex)
            {
                Logger.Instance.LogMessage("Error disconnecting from server: {0}", ex.Message);
            }
        }
    }
}
